<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
        integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

    <title>碧蓝航线CD计算器-航母装备选择</title>
    <style>
        input[type=number] {
            width: 80px;
        }

        input.name {
            width: 100px;
        }

        div.layer {
            display: inline-block;
        }

        div.shipinfo {
            margin-top: 15px;
            margin-bottom: 15px;
        }

        .slot input[type=number] {
            width: 30px;
        }

        #ship-name {
            min-width: 100px;
            display: inline-block;
        }

        table {
            text-align: center;
        }

        td.disp-equip {
            width: 200px;
        }

        td.disp-cd {
            width: 80px;
        }

        #cover {
            position: fixed;
            left: 0px;
            top: 0px;
            background: rgba(0, 0, 0, 0.4);
            width: 100%;
            height: 100%;
            display: none;
            z-index: 10;
            cursor: pointer;
        }

        #modal {
            position: fixed;
            left: 0;
            width: 100%;
            top: 20%;
            height: 80%;
            padding: 20px 20px 20px 20px;
            background-color: #fff;
            display: none;
            z-index: 11;
        }

        #chart-container {
            position: fixed;
            left: 0;
            bottom: 0px;
            width: 100%;
            height: 300px;
            background: #fafafa;
            z-index: 9;
        }

        #results {
            padding-bottom: 300px;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            margin: 0 0 0 0;
        }

        .slot-options label {
            margin: 10px 10px 10px 10px;
            display: inline-flex;
        }

        label.disabled {
            color: gray;

        }

        div.slot-buttons {
            height: 100px;
        }

        div.slot-options {
            overflow-y: scroll;
            height: 400px;
        }

        table {
            border-collapse: collapse;
        }

        tr {
            cursor: pointer;
            border: 1px solid black;
        }

        div.container {
            margin-left: 10px;
            margin-right: 10px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>碧蓝航线CD计算器-航母装备选择</h1>
        <a href="./">CD计算器</a> <button onclick="resetData(); initAll();">重置数据(出现问题时请尝试点击)</button>
        <br><br>
    </div>
    <div id="extra-reload-inc" class="container">
        <label>
            命中延迟
            <input type="number" name="offset-cv" id="offset-cv" value="0" min="0">
        </label>
        <label>
            攻击持续时间
            <input type="number" name="duration-cv" id="duration-cv" value="1" min="1">
        </label>
        装填加成:
        <label>
            舰队科技
            <input type="number" class="affect-cd" name="tech-inc-cv" id="tech-inc-cv" value="0" min="0">
        </label>
        <label>
            指挥猫
            <input type="number" class="affect-cd" name="cat-inc-cv" id="cat-inc-cv" value="0" min="0">
        </label>
        <br>
        <label>
            公共进图延迟
            <input type="number" name="offset-all" id="offset-all" value="0" min="0">
        </label>
    </div>
    <hr>
    <div class="shipinfo ship-cv container">
        <label>
            舰娘
            <select name="name" id="ship-name">
                <option value="custom">自定义</option>
            </select>
        </label>
        <br>
        <div class="slot slot0">
            舰载机1:
            <label><input type="number" name="slot0-cnt" value="1" min="1" max="9"></label>
            <label>战斗机<input type="checkbox" name="slot0-z"></label>
            <label>轰炸机<input type="checkbox" name="slot0-h"></label>
            <label>鱼雷机<input type="checkbox" name="slot0-y"></label>
            <button onclick="selectSlotOption(0)">设置选项</button>
            <span class="option-desc"></span>
        </div>

        <div class="slot slot1">
            舰载机2:
            <label><input type="number" name="slot1-cnt" value="1" min="0" max="9"></label>
            <label>战斗机<input type="checkbox" name="slot1-z"></label>
            <label>轰炸机<input type="checkbox" name="slot1-h"></label>
            <label>鱼雷机<input type="checkbox" name="slot1-y"></label>
            <button onclick="selectSlotOption(1)">设置选项</button>
            <span class="option-desc"></span>
        </div>

        <div class="slot slot2">
            舰载机3:
            <label><input type="number" name="slot2-cnt" value="1" min="0" max="9"></label>
            <label>战斗机<input type="checkbox" name="slot2-z"></label>
            <label>轰炸机<input type="checkbox" name="slot2-h"></label>
            <label>鱼雷机<input type="checkbox" name="slot2-y"></label>
            <button onclick="selectSlotOption(2)">设置选项</button>
            <span class="option-desc"></span>
        </div>
        <div class="cd">
            <label>
                首轮射速加成
                <input class="ship-input firstbuff" type="number" name="firstCDBuff" min="0" max="100">%
            </label>
            <label>
                射速加成
                <input class="ship-input buff affect-cd" type="number" name="CDBuff" max="100">%
            </label>
            <label>
                额外装填
                <input class="ship-input reloadbuff affect-cd" type="number" name="reloadBuff" min="0">%
            </label>
            <label>
                面板装填
                <input class="ship-input reload affect-cd" type="number" name="reload" min="0">
            </label>
            <br>
        </div>
    </div>
    <hr>
    <div id="target" class="container">
        <label>
            战斗时间
            <input type="number" name="max-duration" id="max-duration">
            s
        </label>
        &nbsp;
        <label>
            按剩余时间显示
            <input type="checkbox" name="time-inv" id="time-inv">
        </label>
        <br>
        对轴目标
        <label>
            类型
            <select name="type">
                <option value="fixed">周期性</option>
                <option value="predefined">预定义</option>
            </select>
        </label>
        <div class="layer buff fixed">
            <label>
                CD
                <input type="number" min="0" step="any" name="cd">
            </label>
            <label>
                持续时间
                <input type="number" min="0" step="any" name="duration">
            </label>
            <label>
                首轮CD
                <input type="number" min="0" step="any" name="offset">
            </label>
        </div>
        <div class="layer buff predefined">
            <input name="data" style="width: 80%" placeholder="请输入 start,end,start,end 格式的时间记录"></textarea>
        </div>
        <hr>
    </div>
    <div id="cover" class="modal" onclick="finishSelect()">
        <div style="text-align: center; color: white; font-size: 3em; margin-top: 5%;">点击遮罩层退出</div>
    </div>
    <div id="modal" class="modal">
        <div class="slot-buttons">
            选中:
            <button class="slot-option" data-q="input.slot-option" data-set="1">全部</button> |
            <button class="slot-option" data-q="input.slot-option.fast" data-set="1">调速</button>
            <button class="slot-option" data-q="input.slot-option.damage" data-set="1">伤害</button> |
            <button class="slot-option z" data-q="input.slot-option.z" data-set="1">战斗机</button>
            <button class="slot-option h" data-q="input.slot-option.h" data-set="1">轰炸机</button>
            <button class="slot-option y" data-q="input.slot-option.y.js" data-set="1">集束雷</button>
            <button class="slot-option y" data-q="input.slot-option.y.px" data-set="1">平行雷</button>
            <br>
            取消:
            <button class="slot-option" data-q="input.slot-option" data-set="0">全部</button> |
            <button class="slot-option" data-q="input.slot-option.fast" data-set="0">调速</button>
            <button class="slot-option" data-q="input.slot-option.damage" data-set="0">伤害</button> |
            <button class="slot-option z" data-q="input.slot-option.z" data-set="0">战斗机</button>
            <button class="slot-option h" data-q="input.slot-option.h" data-set="0">轰炸机</button>
            <button class="slot-option y" data-q="input.slot-option.y.js" data-set="0">集束雷</button>
            <button class="slot-option y" data-q="input.slot-option.y.px" data-set="0">平行雷</button>
            <br>
        </div>
        <div class="slot-options">
            <div class="slot-option z"></div><br>
            <div class="slot-option h"></div><br>
            <div class="slot-option y"></div><br>
        </div>
    </div>
    <div id="chart-container">
        <div style="text-align: center; position: relative; top: 0;">
            <div class="btn btn-primary btn-sm" onclick="toggleHeight()"
                style="position: absolute; z-index: 10; width: 60px;">&#8593;</div>
        </div>
        <div id="chart" style="height: 100%;"></div>
    </div>
    <div id="results" class="container"></div>

    <!-- 模板开始 -->
    <template id="result-table-template">
        <table>
            <thead>
                <tr>
                    <th>舰载机1</th>
                    <th>舰载机2</th>
                    <th>舰载机3</th>
                    <th>面板CD</th>
                    <th>首轮CD</th>
                    <th>实际CD</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    </template>
</body>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"
    integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"
    integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
    crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.1.2/dist/echarts.min.js"
    integrity="sha256-TI0rIaxop+pDlHNVI6kDCFvmpxNYUnVH/SMjknZ/W0Y=" crossorigin="anonymous"></script>
<script src="js/storage.js"></script>
<script src="js/utils.js"></script>
<script src="js/cd.js"></script>
<script src="js/render.js?v=2"></script>
<script>
    const STORE_KEY = 'AzurLaneCDTool-CacheData-CVHelper';
    let data;
    let shipData, aircraftData;
    let targetSlot;
    let cdResults = [];
    function saveData() {
        localStorage.setItem(STORE_KEY, JSON.stringify(data));
    }
    window.addEventListener('beforeunload', saveData);

    function toggleHeight() {
        var height = $('#chart-container')[0].style.height;
        if (!height) {
            $('#chart-container')[0].style.height = '80%';
            $('#chart-container .btn').html('&#8595;');
        } else {
            $('#chart-container')[0].style.height = '';
            $('#chart-container .btn').html('&#8593;');
        }
        window.chart.resize();
    }
    function selectSlotOption(idx) {
        let slot = data.ship.slots[idx];
        targetSlot = idx;
        if (slot.options) {
            $('#modal input').each((idx, val) => {
                let $val = $(val);
                val.checked = false;
            });
            for (let item of slot.options) {
                $(`#modal .slot-option[name="${item.name}"]`)[0].checked = true;
            }
        }
        for (let key of ['z', 'h', 'y']) {
            if (!slot[key]) {
                $('.slot-option.' + key).prop('disabled', true);
                $('.slot-option.' + key).addClass('disabled');
            } else {
                $('.slot-option.' + key).prop('disabled', null);
                $('.slot-option.' + key).removeClass('disabled');
            }
        }
        $('#modal button').on('click', (evt) => {
            let $btn = $(evt.target);
            let set = Boolean(parseFloat($btn.data('set')));
            $($btn.data('q')).not('[disabled]').each((idx, val) => {
                val.checked = set;
            });
        })
        $('.modal').show();
    }
    function finishSelect() {
        $('.modal').hide();
        let slot = data.ship.slots[targetSlot];
        slot.options = [];
        $('#modal input[type=checkbox]').not('[disabled]').each((idx, val) => {
            if (!val.checked) {
                return
            }
            slot.options.push({
                name: val.name,
                cd: $(val).data('cd'),
                type: $(val).data('type'),
            });
        });
        $(`div.slot.slot${targetSlot} span.option-desc`).text(`${slot.options.length}种舰载机`);
        data.chartIdx = 0;
        updateResult();
    }
    function resetData() {
        data = {
            ship: {
                name: 'custom',
                type: 'CV',
                slots: [
                    { cnt: 1, z: 1, h: 0, y: 0 },
                    { cnt: 1, z: 1, h: 0, y: 0 },
                    { cnt: 0, z: 0, h: 0, y: 0 },
                ],
                reload: null,
                firstCDBuff: 0,
                CDBuff: 0,
                reloadBuff: 0,
            },
            target: {
                type: 'fixed',
                cd: 20,
                duration: 10,
                offset: null,
                data: '',
            },
            reload: {
                tech: {
                    CV: 0,
                },
                cat: {
                    CV: 0,
                }
            },
            chartIdx: 0,
            config: {
                maxDuration: 180,
                showTimeAsLeft: false,
                offset: {
                    ALL: 1.5,
                    CV: 1,
                },
                duration: {
                    CV: 3,
                },
            }
        };
        saveData();
    }
    function product(a, b, c) {
        let res = [];
        return res;
    }
    function getAllChoices(slots) {
        let groups = [];
        for (let slot of slots) {
            let group = {
                cnt: slot.cnt,
                choices: slot.options
            };
            if (group.choices.length === 0) {
                group.choices = [{ name: '-', cd: 0 }];
                group.cnt = 0;
            }
            groups.push(group);
        }
        let a = groups[0], b = groups[1], c = groups[2];
        console.log('总选项数量', a.choices.length, b.choices.length, c.choices.length, a.choices.length * b.choices.length * c.choices.length);
        let res = [];
        for (let sa of a.choices) {
            for (let sb of b.choices) {
                for (let sc of c.choices) {
                    let cd = (sa.cd * a.cnt + sb.cd * b.cnt + sc.cd * c.cnt) / (a.cnt + b.cnt + c.cnt);
                    let choice = [sa, sb, sc];
                    res.push({ cd, choice });
                }
            }
        }
        res.sort((a, b) => {
            return a.cd - b.cd;
        });
        return res;
    }
    function updateChartOption(idx) {
        if (!isNaN(parseFloat(idx))) {
            data.chartIdx = idx;
        }
        $(`#results table tr`).css('background', '')
        $('#results table tbody tr').eq(data.chartIdx).css("background-color", "#6cf")
        console.log('chartIdx', data.chartIdx, cdResults)
        let item = cdResults[data.chartIdx];
        if (!item) {
            if (cdResults.length === 0) {
                return
            }
            data.chartIdx = 0;
        }
        let name = [];
        item.choice.forEach((c) => {
            if (c.name !== '-') {
                name.push(c.name)
            }

        })
        let record = {
            ships: [{
                name: name.join('\n'),
                type: 'CV',
                realCD: item.realCD - extraCD.CV,
                firstCDBuff: data.ship.firstCDBuff,
                CDBuff: data.ship.CDBuff,
                reloadBuff: data.ship.reloadBuff,
                bindSkills: [],
            }],
            buffs: [{
                ...data.target,
                name: '目标Buff'
            }],
            config: data.config
        }
        let { categories, chartData } = buildOption(record);
        chartData.title = '';
        window.setChartOption(categories, chartData, record.config, {
            title: { show: false }, grid: {
                top: '2%',
            }
        });
    }
    function updateResult() {
        console.log('updateResult', data.ship, data.target);
        let $res = $('#results');
        $res.html('');
        let comCnt = 1;
        for (let slot of data.ship.slots) {
            if (!slot.options) {
                slot.options = getAllOptions(slot);
            }
            if (slot.options.length > 1) {
                comCnt = comCnt * slot.options.length;
            }
        }
        updateChartOption();
        $res.append(`总选项数量${comCnt}`);
        if (comCnt > 1000) {
            $res.append(', 请减少舰载机选项数量!');
            return;
        } else {
            $res.append('.<br>');
        }
        // 计算目标CD对应的舰载机原始CD
        // 实际CD = (装填加成 * 原始CD * 2.2) * 射速加成 + 前后摇
        // 原始CD = (实际CD - 前后摇) / (装填加成 * 射速加成 * 2.2)
        let realReload = (data.ship.reload + data.reload.tech.CV + data.reload.cat.CV) * (1 + (data.ship.reloadBuff || 0) / 100);
        let realRatio = getCDMultiplier(realReload) * (1 - (data.ship.CDBuff || 0) / 100) * 2.2;
        if (!data.ship.reload || !realRatio) {
            $res.append('请补全舰娘数据!');
            return;
        }
        console.log(realRatio);
        cdResults = getAllChoices(data.ship.slots);
        console.log('计算完毕. 可选数量: ', cdResults.length);
        // 计算面板CD
        // 面板CD = 原始CD * 面板装填加成 * 2.2
        $res.append(`共得到${cdResults.length}种可选方案`);
        if (cdResults.length === 0) {
            return;
        }
        if (data.chartIdx >= cdResults.length) {
            data.chartIdx = 0;
        }
        let dispLimit = 50;
        if (cdResults.length > dispLimit) {
            $res.append(', 将显示前' + dispLimit + '种');
            cdResults.splice(dispLimit, cdResults.length - dispLimit);
        }
        $res.append('.<br>');
        let $tbl = $(getTemplate('result-table-template'));
        $res.append($tbl);

        let dispRatio = getCDMultiplier(data.ship.reload + data.reload.tech.CV) * 2.2;
        let firstRatio = realRatio * (1 - (data.ship.firstCDBuff || 0) / 100);
        let $tbody = $tbl.find('tbody');
        for (let [idx, item] of cdResults.entries()) {
            let dispCD = (item.cd * dispRatio);
            item.realCD = (item.cd * realRatio + extraCD.CV);
            item.firstCD = (item.cd * firstRatio);
            let tr = [`<tr onclick="updateChartOption(${idx})">`]
            item.choice.forEach((c) => {
                tr.push('<td class="disp-equip">' + c.name + '</td>')
            });
            tr.push(`
            <td class="disp-cd">${dispCD.toFixed(2)}</td>
            <td class="disp-cd">${item.firstCD.toFixed(4)}</td>
            <td class="disp-cd">${item.realCD.toFixed(4)}</td>`)
            tr.push('</tr>');
            $tbody.append(tr.join(''));
        }
        updateChartOption();
        return;
    }
    function getAllOptions(slot) {
        let res = [];
        for (let key of ['z', 'h', 'y']) {
            if (slot[key]) {
                res.push(...aircraftData[key]);
            }
        }
        return res;
    }
    function onShipSelect() {
        let shipId = $('#ship-name').val();
        if (shipId !== 'custom') {
            let shipInfo = shipData[shipId];
            console.log('更新', shipId, shipInfo.name);
            for (let i of [0, 1, 2]) {
                let slot = data.ship.slots[i];
                let src = shipInfo.slots[i] || {};
                for (let key of ['cnt', 'z', 'h', 'y']) {
                    slot[key] = src[key] || 0;
                }
                if (slot.options) {
                    for (let i = 0; i < slot.options.length;) {
                        if (slot[slot.options[i].type]) {
                            i++;
                        } else {
                            slot.options.splice(i, 1);
                        }
                    }
                    if (slot.options.length === 0) {
                        slot.options = null;
                    }
                }
                if (!slot.options) {
                    slot.options = getAllOptions(slot);
                }
            }
            for (let key of ['firstCDBuff', 'CDBuff', 'reload']) {
                data.ship[key] = shipInfo[key] || 0;
            }

        }
        $(`.slot input`).off();
        $(`.cd input`).off();
        data.chartIdx = 0;
        updateDomData();
        updateResult();
    }
    function updateDomData() {
        for (let i of [0, 1, 2]) {
            let slot = data.ship.slots[i];
            bindInput(slot, 'cnt', `.slot input[name=slot${i}-cnt]`, updateResult);
            for (let key of ['z', 'h', 'y']) {
                bindCheckbox(slot, key, `.slot input[name=slot${i}-${key}]`, updateResult);
            }
            if (slot.options) {
                $(`div.slot.slot${i} span.option-desc`).text(`${slot.options.length}种舰载机`);
            }
        }
        if ($('#ship-name').val() === 'custom') {
            $('.slot input').prop('disabled', null);
        } else {
            $('.slot input').prop('disabled', true);
        }
        for (let name of ['reload', 'reloadBuff', 'CDBuff', 'firstCDBuff']) {
            bindInput(data.ship, name, `.cd input[name=${name}]`, updateResult);
        }
    }
    function loadDataAndDom() {
        try {
            data = JSON.parse(localStorage.getItem(STORE_KEY));
        } catch (e) { }
        if (!data) {
            resetData();
        }
        console.log('LoadData', data);
        // 删除当前绑定的事件
        $('input, select, button').off();
        bindInput(data.ship, 'name', '#ship-name', onShipSelect);

        updateDomData();

        bindInput(data.reload.tech, 'CV', '#tech-inc-cv', updateResult);
        bindInput(data.reload.cat, 'CV', '#cat-inc-cv', updateResult);

        bindInput(data.config, 'maxDuration', '#max-duration', updateResult);
        bindCheckbox(data.config, 'showTimeAsLeft', '#time-inv', updateResult);
        bindInput(data.config.offset, 'ALL', '#offset-all', updateResult);
        bindInput(data.config.offset, 'CV', '#offset-cv', updateResult);
        bindInput(data.config.duration, 'CV', '#duration-cv', updateResult);
    }
    async function initAll() {
        let resp = await fetch('data/ships.json');
        shipData = await resp.json();
        let resp2 = await fetch('data/aricrafts.json?v=3');
        aircraftData = await resp2.json();
        for (let key in aircraftData) {
            let target = $('#modal div.slot-options div.slot-option.' + key);
            for (let aircraft of aircraftData[key]) {
                let cls = ['slot-option', key];
                if (aircraft.tags) {
                    cls.push(...aircraft.tags);
                }
                if (aircraft.cd < 10) {
                    cls.push('fast')
                }
                target.append(`
                <label class="${cls.join(' ')}">${aircraft.name}
                <input data-cd="${aircraft.cd}" data-type="${key}" 
                class="${cls.join(' ')}" name="${aircraft.name}" type="checkbox">
                </label>`)
            }
        }
        let $dom = $('#ship-name');
        for (let key in shipData) {
            $dom.append(`<option value="${key}">${shipData[key].name}</option>`);
        }
        loadDataAndDom();


        bindInput(data.target, 'minCD', 'input[name=target-cd-min]', updateResult);
        bindInput(data.target, 'maxCD', 'input[name=target-cd-max]', updateResult);

        let $node = $('#target');
        for (let name of ['type', 'cd', 'duration', 'offset', 'data']) {
            bindInput(data.target, name, $node.find(`[name=${name}]`), updateResult);
        }
        let $type = $node.find('[name=type]');
        function updateDisplay() {
            console.log('updateDisplay', $type)
            console.log($node.find('div.buff'));
            $node.find('div.buff').hide();
            $node.find('div.buff.' + $type.val()).show();
        }
        $type.on('change', updateDisplay);
        updateDisplay();
        updateResult();
    }
    try {
        initAll();
    } catch (e) {
        resetData();
        initAll();
    }
</script>

</html>